package com.devmarvel.creditcardentry.library;

import com.devmarvel.creditcardentry.ResourceTable;
import com.devmarvel.creditcardentry.fields.CreditCardText;
import com.devmarvel.creditcardentry.internal.CreditCardEntry;
import com.devmarvel.creditcardentry.util.Constants;
import com.devmarvel.creditcardentry.util.ResUtil;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.DependentLayout;
import ohos.agp.components.DirectionalLayout;
import ohos.agp.components.Image;
import ohos.agp.components.StackLayout;
import ohos.agp.components.Text;
import ohos.agp.components.element.Element;
import ohos.agp.utils.Color;
import ohos.agp.utils.LayoutAlignment;
import ohos.app.Context;

public class CreditCardForm extends DependentLayout {

    private CreditCardEntry entry;
    private boolean includeExp = true;
    private boolean includeSecurity = true;
    private boolean includeZip = true;
    private boolean includeHelper;
    private Color textHelperColor;
    private Element inputBackground;
    private boolean useDefaultColors;
    private boolean animateOnError;
    private String cardNumberHint = "1234 5678 9012 3456";

    // custom attributes
    private static final String card_number_hint = "card_number_hint";
    private static final String include_exp = "include_exp";
    private static final String include_security = "include_security";
    private static final String include_zip = "include_zip";
    private static final String include_helper = "include_helper";
    private static final String helper_text_color = "helper_text_color";
    private static final String input_background = "input_background";
    private static final String default_text_colors = "default_text_colors";
    private static final String animate_on_error = "animate_on_error";

    public CreditCardForm(Context context) {
        this(context, null);
    }

    public CreditCardForm(Context context, AttrSet attrs) {
        this(context, attrs, "");
    }

    public CreditCardForm(Context context, AttrSet attrs, String defStyle) {
        super(context, attrs, defStyle);
        // If the attributes are available, use them to color the icon
        if (attrs != null) {

            this.cardNumberHint = attrs.getAttr(card_number_hint).isPresent() ?
                    attrs.getAttr(card_number_hint).get().getStringValue() : null;
            this.includeExp = !attrs.getAttr(include_exp).isPresent() || attrs.getAttr(include_exp).get().getBoolValue();
            this.includeSecurity = !attrs.getAttr(include_security).isPresent() || attrs.getAttr(include_security).get().getBoolValue();
            this.includeZip = !attrs.getAttr(include_zip).isPresent() || attrs.getAttr(include_zip).get().getBoolValue();
            this.includeHelper = !attrs.getAttr(include_helper).isPresent() || attrs.getAttr(include_helper).get().getBoolValue();
            this.textHelperColor = attrs.getAttr(helper_text_color).isPresent() ?
                    attrs.getAttr(helper_text_color).get().getColorValue() : ResUtil.getNewColor(context, ResourceTable.Color_text_helper_color);
            this.inputBackground = attrs.getAttr(input_background).isPresent() ?
                    attrs.getAttr(input_background).get().getElement() : null;
            this.useDefaultColors = attrs.getAttr(default_text_colors).isPresent() && attrs.getAttr(default_text_colors).get().getBoolValue();
            this.animateOnError = !attrs.getAttr(animate_on_error).isPresent() || attrs.getAttr(animate_on_error).get().getBoolValue();
        }

        // defaults if not set by user
        if (cardNumberHint == null) cardNumberHint = "1234 5678 9012 3456";
        if (textHelperColor == null) textHelperColor = ResUtil.getNewColor(context, ResourceTable.Color_text_helper_color);
        if (inputBackground == null) {
            //noinspection deprecation
            inputBackground = ResUtil.getShapeElement(context, ResourceTable.Graphic_background_white);
        }
        init(context, attrs, defStyle);
    }

    private void init(Context context, AttrSet attrs, String style) {
        // the wrapper layout
        DirectionalLayout layout = new DirectionalLayout(context);

        layout.setOrientation(Component.HORIZONTAL);
        //ignore RTL layout direction
        layout.setLayoutDirection(LayoutDirection.LTR);

        layout.setId(Constants.Ids.cc_form_layout);
        LayoutConfig params = new LayoutConfig(LayoutConfig.MATCH_PARENT, LayoutConfig.MATCH_CONTENT);
        params.addRule(DependentLayout.LayoutConfig.ALIGN_PARENT_LEFT);
        params.addRule(DependentLayout.LayoutConfig.ALIGN_PARENT_TOP);
        params.addRule(DirectionalLayout.HORIZONTAL);
        params.setMargins(0, 0, 0, 0);
        layout.setLayoutConfig(params);
        layout.setPadding(10, 10, 10, 10);
        //noinspection deprecation
        layout.setBackground(inputBackground);

        // set up the card image container and images
        StackLayout cardImageFrame = new StackLayout(context);
        DirectionalLayout.LayoutConfig frameParams = new DirectionalLayout.LayoutConfig(LayoutConfig.MATCH_CONTENT, LayoutConfig.MATCH_CONTENT);
        frameParams.alignment = LayoutAlignment.VERTICAL_CENTER;
        cardImageFrame.setLayoutConfig(frameParams);
        cardImageFrame.setFocusable(FOCUS_ENABLE);
        cardImageFrame.setTouchFocusable(true);
        cardImageFrame.setPadding(10, 0, 0, 0);

        Image cardFrontImage = new Image(context);
        LayoutConfig layoutParams = new LayoutConfig(LayoutConfig.MATCH_CONTENT, LayoutConfig.MATCH_CONTENT);
        cardFrontImage.setLayoutConfig(layoutParams);
        cardFrontImage.setImageElement(ResUtil.getPixelMapDrawable(context, CardType.INVALID.frontResource));
        cardImageFrame.addComponent(cardFrontImage);

        Image cardBackImage = new Image(context);
        layoutParams = new DependentLayout.LayoutConfig(LayoutConfig.MATCH_CONTENT, LayoutConfig.MATCH_CONTENT);
        cardBackImage.setLayoutConfig(layoutParams);
        cardBackImage.setImageElement(ResUtil.getPixelMapDrawable(context, CardType.INVALID.backResource));
        cardBackImage.setVisibility(Component.HIDE);
        cardImageFrame.addComponent(cardBackImage);
        layout.addComponent(cardImageFrame);

        // add the data entry form
        DirectionalLayout.LayoutConfig entryParams = new DirectionalLayout.LayoutConfig(LayoutConfig.MATCH_CONTENT, LayoutConfig.MATCH_CONTENT);
        entryParams.alignment = LayoutAlignment.VERTICAL_CENTER;
        entry = new CreditCardEntry(context, includeExp, includeSecurity, includeZip, attrs, style);
        entry.setId(Constants.Ids.cc_entry);

        // this obnoxious 6 for bottom padding is to make the damn text centered on the image... if you know a better way... PLEASE HELP
        entry.setPadding(0, 0, 0, 6);
        entry.setLayoutConfig(entryParams);

        // set any passed in attrs
        entry.setCardImageView(cardFrontImage);
        entry.setBackCardImage(cardBackImage);
        entry.setCardNumberHint(cardNumberHint);

        entry.setAnimateOnError(animateOnError);

        this.addComponent(layout);

        // set up optional helper text view
        if (includeHelper) {
            Text textHelp = new Text(context);
            textHelp.setId(Constants.Ids.text_helper);
            textHelp.setTextSize(14, Text.TextSizeType.FP);
            textHelp.setText(context.getString(ResourceTable.String_CreditCardNumberHelp));
            if (useDefaultColors) {
                textHelp.setTextColor(this.textHelperColor);
            }
            layoutParams = new LayoutConfig(LayoutConfig.MATCH_CONTENT, LayoutConfig.MATCH_CONTENT);
            layoutParams.addRule(LayoutConfig.BELOW, layout.getId());
            layoutParams.addRule(LayoutConfig.HORIZONTAL_CENTER);
            layoutParams.setMargins(0, 15, 0, 20);
            textHelp.setLayoutConfig(layoutParams);
            entry.setTextHelper(textHelp);
            this.addComponent(textHelp);
        }

        layout.addComponent(entry);
    }

    public void setOnCardValidCallback(CardValidCallback callback) {
        entry.setOnCardValidCallback(callback);
    }

    /**
     * all internal components will be attached this same focus listener
     */
    @Override
    public void setFocusChangedListener(FocusChangedListener l) {
        entry.setFocusChangedListener(l);
    }

    @SuppressWarnings("unused")
    public boolean isCreditCardValid() {
        return entry.isCreditCardValid();
    }

    @SuppressWarnings("unused")
    public CreditCard getCreditCard() {
        return entry.getCreditCard();
    }

    /**
     * request focus for the credit card field
     */
    @SuppressWarnings("unused")
    public void focusCreditCard() {
        entry.focusCreditCard();
    }

    /**
     * request focus for the expiration field
     */
    @SuppressWarnings("unused")
    public void focusExp() {
        entry.focusExp();
    }

    /**
     * request focus for the security code field
     */
    @SuppressWarnings("unused")
    public void focusSecurityCode() {
        entry.focusSecurityCode();
    }

    /**
     * request focus for the zip field (IF it's enabled)
     */
    @SuppressWarnings("unused")
    public void focusZip() {
        entry.focusZip();
    }

    /**
     * clear and reset the entire form
     */
    @SuppressWarnings("unused")
    public void clearForm() {
        entry.clearAll();
    }

    /**
     * @param cardNumber     the card number to show
     * @param focusNextField true to go to next field (only works if the number is valid)
     */
    public void setCardNumber(String cardNumber, boolean focusNextField) {
        entry.setCardNumber(cardNumber, focusNextField);
    }

    /**
     * @param expirationDate the exp to show
     * @param focusNextField true to go to next field (only works if the number is valid)
     */
    @SuppressWarnings("unused")
    public void setExpDate(String expirationDate, boolean focusNextField) {
        entry.setExpDate(expirationDate, focusNextField);
    }

    /**
     * @param securityCode   the security code to show
     * @param focusNextField true to go to next field (only works if the number is valid)
     */
    @SuppressWarnings("unused")
    public void setSecurityCode(String securityCode, boolean focusNextField) {
        entry.setSecurityCode(securityCode, focusNextField);
    }

    /**
     * @param zip            the zip to show
     * @param focusNextField true to go to next field (only works if the number is valid)
     */
    @SuppressWarnings("unused")
    public void setZipCode(String zip, boolean focusNextField) {
        entry.setZipCode(zip, focusNextField);
    }

    /**
     * helper & hint setting
     **/

    public void setCreditCardTextHelper(String text) {
        entry.setCreditCardTextHelper(text);
    }

    public void setCreditCardTextHint(String text) {
        entry.setCreditCardTextHint(text);
    }

    public void setExpDateTextHelper(String text) {
        entry.setExpDateTextHelper(text);
    }

    public void setExpDateTextHint(String text) {
        entry.setExpDateTextHint(text);
    }

    public void setSecurityCodeTextHelper(String text) {
        entry.setSecurityCodeTextHelper(text);
    }

    public void setSecurityCodeTextHint(String text) {
        entry.setSecurityCodeTextHint(text);
    }

    public void setZipCodeTextHelper(String text) {
        entry.setZipCodeTextHelper(text);
    }

    public void setZipCodeTextHint(String text) {
        entry.setZipCodeTextHint(text);
    }

    public CreditCardEntry getCreditCardEntry() {
        return entry;
    }
}

